# Copyright 2022 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc/toolchains:args.bzl", "cc_args")
load("@rules_cc//cc/toolchains:toolchain.bzl", "cc_toolchain")

licenses(["notice"])

cc_library(
    name = "newlib_os_interface_stubs",
    srcs = ["newlib_os_interface_stubs.cc"],
    implementation_deps = ["//pw_assert:check"],
    linkopts = [
        "-Wl,--wrap=__sread",
        "-Wl,--wrap=__swrite",
        "-Wl,--wrap=__sseek",
        "-Wl,--wrap=__sclose",
    ],
    # Only built as part of the ARM GCC toolchain.
    tags = ["manual"],
    visibility = ["//visibility:public"],
    alwayslink = 1,
)

cc_library(
    name = "arm_none_eabi_gcc_support",
    # Only built as part of the ARM GCC toolchain.
    tags = ["manual"],
    visibility = ["//visibility:public"],
    deps = [
        ":newlib_os_interface_stubs",
        "//pw_toolchain:wrap_abort",
    ],
)

# Additional arm_gcc specific warning flags
cc_args(
    name = "warnings",
    actions = [
        "@rules_cc//cc/toolchains/actions:compile_actions",
    ],
    args = [
        # This can't be in common, because proto headers in host builds trigger
        "-Wundef",
        # Silence the really verbose ARM warnings.
        "-Wno-psabi",
    ],
)

cc_args(
    name = "thumb_abi",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mabi=aapcs",
        "-mthumb",
    ],
)

cc_args(
    name = "unified_asm_syntax",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-masm-syntax-unified",
    ],
)

# This flag prevents Arm GCC from printing the resolved paths of symlinks,
# which prevents compilation actions from being hermetic. See
# https://github.com/bazelbuild/bazel/issues/21981 and
# https://pwbug.dev/319665090.
cc_args(
    name = "no_canonical_system_headers",
    actions = [
        "@rules_cc//cc/toolchains/actions:compile_actions",
    ],
    args = [
        "-fno-canonical-system-headers",
    ],
)

cc_args(
    name = "cortex_common",
    actions = [
        "@rules_cc//cc/toolchains/actions:compile_actions",
    ],
    args = [
        "-ffreestanding",
        "-specs=nano.specs",
        "-specs=nosys.specs",
    ],
)

cc_args(
    name = "cortex_common_link",
    actions = ["@rules_cc//cc/toolchains/actions:link_actions"],
    args = [
        "-Wl,--gc-sections",
        "-specs=nano.specs",
        "-specs=nosys.specs",
        "-lstdc++",
        "-lnosys",
        "-lc",
        "-lm",
        "-Wl,--no-warn-rwx-segment",
    ],
)

cc_args(
    name = "cortex-m0",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mcpu=cortex-m0",
        "-mfloat-abi=soft",
    ],
)

cc_args(
    name = "cortex-m0plus",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mcpu=cortex-m0plus",
        "-mfloat-abi=soft",
    ],
)

cc_args(
    name = "cortex-m3",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mcpu=cortex-m3",
        "-mfloat-abi=soft",
    ],
)

cc_args(
    name = "cortex-m4",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mcpu=cortex-m4",
        "-mfloat-abi=hard",
        "-mfpu=fpv4-sp-d16",
        # Used by some pigweed tests/targets to correctly handle hardware FPU
        # behavior.
        "-DPW_ARMV7M_ENABLE_FPU=1",
    ],
)

cc_args(
    name = "cortex-m7",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mcpu=cortex-m7",
        "-mfloat-abi=hard",
        "-mfpu=fpv5-d16",
        # Used by some pigweed tests/targets to correctly handle hardware FPU
        # behavior.
        "-DPW_ARMV7M_ENABLE_FPU=1",
    ],
)

cc_args(
    name = "cortex-m33",
    actions = [
        "@rules_cc//cc/toolchains/actions:assembly_actions",
        "@rules_cc//cc/toolchains/actions:compile_actions",
        "@rules_cc//cc/toolchains/actions:link_actions",
    ],
    args = [
        "-mcpu=cortex-m33",
        "-mfloat-abi=hard",
        "-mfpu=fpv5-sp-d16",
        # Used by some pigweed tests/targets to correctly handle hardware FPU
        # behavior.
        "-DPW_ARMV7M_ENABLE_FPU=1",
    ],
)

cc_toolchain(
    name = "arm_gcc_toolchain_cortex-m",
    args = [
        "//pw_toolchain/cc/args:oz",
        "//pw_toolchain/cc/args:debugging",
        "//pw_toolchain/cc/args:reduced_size",
        "//pw_toolchain/cc/args:no_canonical_prefixes",
        "//pw_toolchain/cc/args:no_rtti",
        "//pw_toolchain/cc/args:wno_register",
        "//pw_toolchain/cc/args:wnon_virtual_dtor",
        "//pw_toolchain/cc/args:common_warnings",
        "//pw_toolchain/cc/args:color_diagnostics",
    ] + select({
        "//pw_build/constraints/arm:cortex-m0": [":cortex-m0"],
        "//pw_build/constraints/arm:cortex-m0plus": [":cortex-m0plus"],
        "//pw_build/constraints/arm:cortex-m3": [":cortex-m3"],
        "//pw_build/constraints/arm:cortex-m33": [":cortex-m33"],
        "//pw_build/constraints/arm:cortex-m4": [":cortex-m4"],
        "//pw_build/constraints/arm:cortex-m7": [":cortex-m7"],
        "//pw_build/constraints/arm:none": [],
    }) + [
        ":thumb_abi",
        # TODO(b/353576440): Enable unified assembly syntax.
        # ":unified_asm_syntax",
        ":cortex_common",
        ":cortex_common_link",
        ":no_canonical_system_headers",
        ":warnings",
        # This should always go last so users can override previous choices.
        "//pw_toolchain/cc/args:extra_toolchain_args",
    ],
    enabled_features = [
        "@rules_cc//cc/toolchains/args:experimental_replace_legacy_action_config_features",
        "//pw_toolchain/cc/capability:compiler_is_gcc",
        "//pw_toolchain/cc/capability:linker_is_gcc",
    ] + select({
        "//pw_toolchain/cc:c++17_enabled": ["//pw_toolchain/cc/args:c++17_feature"],
        "//conditions:default": [],
    }) + select({
        "//pw_toolchain/cc:c++20_enabled": ["//pw_toolchain/cc/args:c++20_feature"],
        "//conditions:default": [],
    }),
    known_features = [
        "@rules_cc//cc/toolchains/args:experimental_replace_legacy_action_config_features",
        "//pw_toolchain/cc/args:c++17_feature",
        "//pw_toolchain/cc/args:c++20_feature",
        "//pw_toolchain/cc/capability:compiler_is_gcc",
        "//pw_toolchain/cc/capability:linker_is_gcc",
    ],
    target_compatible_with = select({
        "//pw_build/constraints/arm:cortex-m0": [],
        "//pw_build/constraints/arm:cortex-m0plus": [],
        "//pw_build/constraints/arm:cortex-m3": [],
        "//pw_build/constraints/arm:cortex-m33": [],
        "//pw_build/constraints/arm:cortex-m4": [],
        "//pw_build/constraints/arm:cortex-m7": [],
        "//pw_build/constraints/arm:none": ["@platforms//:incompatible"],
    }),
    tool_map = "@gcc_arm_none_eabi_toolchain//:all_tools",
    visibility = ["//pw_toolchain:__pkg__"],
)

toolchain(
    name = "arm_gcc_cc_toolchain_cortex-m0",
    target_compatible_with = [
        "//pw_build/constraints/arm:cortex-m0",
    ],
    toolchain = ":arm_gcc_toolchain_cortex-m",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

toolchain(
    name = "arm_gcc_cc_toolchain_cortex-m0plus",
    target_compatible_with = [
        "//pw_build/constraints/arm:cortex-m0plus",
    ],
    toolchain = ":arm_gcc_toolchain_cortex-m",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

toolchain(
    name = "arm_gcc_cc_toolchain_cortex-m3",
    target_compatible_with = [
        "//pw_build/constraints/arm:cortex-m3",
    ],
    toolchain = ":arm_gcc_toolchain_cortex-m",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

toolchain(
    name = "arm_gcc_cc_toolchain_cortex-m4",
    target_compatible_with = [
        "//pw_build/constraints/arm:cortex-m4",
    ],
    toolchain = ":arm_gcc_toolchain_cortex-m",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

toolchain(
    name = "arm_gcc_cc_toolchain_cortex-m7",
    target_compatible_with = [
        "//pw_build/constraints/arm:cortex-m7",
    ],
    toolchain = ":arm_gcc_toolchain_cortex-m",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)

toolchain(
    name = "arm_gcc_cc_toolchain_cortex-m33",
    target_compatible_with = [
        "//pw_build/constraints/arm:cortex-m33",
    ],
    toolchain = ":arm_gcc_toolchain_cortex-m",
    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)
